package d_user

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"jihe.common/protos/user_server/proto"
	"jihe.common/tool"
)

func (s *Model) Create(in *proto.UserDUser) (ret *proto.UserDUser, err error) {
	ret = new(proto.UserDUser)
	in.Id = fmt.Sprintf("%d", tool.GetSnowflakeId())
	in.CreatedAt = time.Now().Format("2006-01-02 15:04:05")
	in.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("INSERT INTO %s (id, openid, unionid, avatar, sex, nickname, phone, created_at, updated_at)VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9)", s.Name)
	_, err = s.Db.Exec(sqlStr, in.Id, in.Openid, in.Unionid, in.Avatar, in.Sex, in.Nickname, in.Phone, in.CreatedAt, in.UpdatedAt)
	if err != nil {
		return
	}
	ret = in
	return
}

func (s *Model) GetByOpenid(openid string) (ret *proto.UserDUser, err error) {
	ret = new(proto.UserDUser)
	sqlStr := fmt.Sprintf("SELECT id, openid, unionid, avatar, sex, nickname, phone, status, created_at, updated_at FROM %s WHERE openid = $1", s.Name)
	err = s.Db.QueryRow(sqlStr, openid).Scan(&ret.Id, &ret.Openid, &ret.Unionid, &ret.Avatar, &ret.Sex, &ret.Nickname, &ret.Phone, &ret.Status, &ret.CreatedAt, &ret.UpdatedAt)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetByUid(uid string) (ret *proto.UserDUser, err error) {
	ret = new(proto.UserDUser)
	sqlStr := fmt.Sprintf("SELECT id, openid, unionid, avatar, sex, nickname, phone, status, created_at, updated_at FROM %s WHERE id = $1", s.Name)
	err = s.Db.QueryRow(sqlStr, uid).Scan(&ret.Id, &ret.Openid, &ret.Unionid, &ret.Avatar, &ret.Sex, &ret.Nickname, &ret.Phone, &ret.Status, &ret.CreatedAt, &ret.UpdatedAt)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetByIds(uids []string) (ret []*proto.UserDUser, err error) {
	args := make([]string, len(uids))
	vals := make([]interface{}, len(uids))
	for k, v := range uids {
		args[k] = fmt.Sprintf("$%d", k+1)
		vals[k] = v
	}

	sqlStr := fmt.Sprintf("select id, nickname, phone from %s where id in ("+strings.Join(args, ",")+")", s.Name)
	rows, err := s.Db.Query(sqlStr, vals...)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.UserDUser{}
		err = rows.Scan(&item.Id, &item.Nickname, &item.Phone)
		if err != nil {
			return
		}
		ret = append(ret, item)
	}
	return
}

func (s *Model) UpdateInfoById(req *proto.UserDUser) (ret *proto.UserDUser, err error) {
	ret = new(proto.UserDUser)
	req.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("UPDATE %s SET avatar = $1, sex = $2, nickname = $3, updated_at = $4 WHERE id = $5", s.Name)
	_, err = s.Db.Exec(sqlStr, req.Avatar, req.Sex, req.Nickname, req.UpdatedAt, req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdatePhotosById(req *proto.UserDUser) (err error) {
	photosB, _ := json.Marshal(req.Photos)
	req.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("UPDATE %s SET photos = $1 WHERE id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, string(photosB), req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateUserSex(req *proto.UserDUser) (err error) {
	sqlStr := fmt.Sprintf("UPDATE %s SET sex = $1 WHERE id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, req.Sex, req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateUserBodyData(req *proto.UserDUser) (err error) {
	bodyDataByte, _ := json.Marshal(req.BodyData)
	sqlStr := fmt.Sprintf("UPDATE %s SET body_data = $1 WHERE id = $2", s.Name)
	_, err = s.Db.Exec(sqlStr, string(bodyDataByte), req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdatePhoneById(req *proto.UserDUser) (ret *proto.UserDUser, err error) {
	ret = new(proto.UserDUser)
	req.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("UPDATE %s SET phone = $1, updated_at = $2 WHERE id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, req.Phone, req.UpdatedAt, req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) UpdateStatusById(req *proto.UserDUser) (err error) {
	req.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	sqlStr := fmt.Sprintf("UPDATE %s SET status = $1, updated_at = $2 WHERE id = $3", s.Name)
	_, err = s.Db.Exec(sqlStr, req.Status, req.UpdatedAt, req.Id)
	if err != nil {
		return
	}
	return
}

func (s *Model) GetList(in *proto.UserListReq) (ret *proto.UserListRes, err error) {
	ret = new(proto.UserListRes)
	sqlStr := "SELECT d_users.id, d_users.openid, d_users.unionid, d_users.avatar, d_users.sex, d_users.nickname, d_users.phone, d_users.status, d_users.created_at, d_users.updated_at, d_users.body_data, d_users.photos FROM d_users left join d_user_audits dua on d_users.id = dua.uid where 1 = 1"
	sqlCountStr := "SELECT COUNT(0) FROM d_users left join d_user_audits dua on d_users.id = dua.uid WHERE 1 = 1"
	conditionSql := ""
	args := make([]interface{}, 0)
	if in.Phone != "" {
		in.Phone = "%" + in.Phone + "%"
		args = append(args, in.Phone)
		conditionSql += fmt.Sprintf(" AND (dua.phone ilike $%d or d_users.phone ilike $%d)", len(args), len(args)+1)
		args = append(args, in.Phone)
	}
	if in.Name != "" {
		in.Name = "%" + in.Name + "%"
		args = append(args, in.Name)
		conditionSql += fmt.Sprintf(" AND (dua.realname ilike $%d or d_users.nickname ilike $%d)", len(args), len(args)+1)
		args = append(args, in.Name)
	}
	_ = s.Db.QueryRow(sqlCountStr+conditionSql, args...).Scan(&ret.Total)
	args = append(args, in.PageSize)
	sqlStr = fmt.Sprintf("%s ORDER BY created_at DESC LIMIT $%d", sqlStr+conditionSql, len(args))
	args = append(args, in.Page*in.PageSize)
	sqlStr += fmt.Sprintf(" OFFSET $%d", len(args))
	rows, e := s.Db.Query(sqlStr, args...)
	if e != nil {
		err = e
		return
	}
	defer rows.Close()
	for rows.Next() {
		item := &proto.UserDUser{}
		var (
			createdAt *time.Time
			updatedAt *time.Time
			bodyData  []byte
			photos    []byte
		)
		err = rows.Scan(&item.Id, &item.Openid, &item.Unionid, &item.Avatar, &item.Sex, &item.Nickname, &item.Phone, &item.Status, &createdAt, &updatedAt, &bodyData, &photos)
		if err != nil {
			return
		}
		if len(bodyData) != 0 {
			_ = json.Unmarshal(bodyData, &item.BodyData)
		}
		if len(photos) != 0 {
			_ = json.Unmarshal(photos, &item.Photos)
		}
		if createdAt != nil {
			item.CreatedAt = createdAt.Format("2006-01-02 15:04:05")
		}
		if updatedAt != nil {
			item.UpdatedAt = updatedAt.Format("2006-01-02 15:04:05")
		}
		ret.List = append(ret.List, item)
	}
	return
}
